using System;
using System.Reflection;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using RikMigrations.Providers;


namespace RikMigrations
{
    public enum MigrationOperation
    {
        /// <summary>
        /// Migrate a database to a specific version (or max)
        /// </summary>
        Migrate,

        /// <summary>
        /// Generate a blank migration
        /// </summary>
        Generate,

        /// <summary>
        /// Generates a set of migrations from a database
        /// </summary>
        AutoGenerate
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            try
            {
				//Console.WriteLine("Press any key to migrate...");
				//Console.ReadKey();

                new Program(args).Run();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error : " + e.Message + "\n" );
                Program.OutputOptions();
            }
        }

        public Program(string[] args)
        {
            ParseCommandLine(args);
        }

        public void Run()
        {
			using( var provider = new MssqlProvider( Output ) )
			{
				switch(Operation)
				{
					case MigrationOperation.Migrate:
					{
						if( ExtraArguments.Count == 0 )
						{
							throw new ArgumentException( "Couldn't Read Specified Arguements" );
						}

						Assembly migrationAssembly = Assembly.LoadFrom( ExtraArguments[0] );
						if( Version == null )
							MigrationManager.UpgradeMax( migrationAssembly,
							                             provider,
							                             ModuleName );
						else
							MigrationManager.MigrateTo( migrationAssembly,
							                            ModuleName,
							                            Version.Value,
							                            provider );
						break;
					}
					case MigrationOperation.AutoGenerate:
					{
						MigrationGenerator.GenerateMigration( provider, Filename, SeparateFiles );
						break;
					}
				}
			}
        }

        #region Properties
        private MigrationOperation? operation = null;
        public MigrationOperation? Operation
        {
            get { return operation; }
            set { operation = value; }
        }

        private string filename;
        public string Filename
        {
            get { return filename; }
            set { filename = value; }
        }

        private int? version;
        public int? Version
        {
            get { return version; }
            set { version = value; }
        }

        private bool separateFiles;
        public bool SeparateFiles
        {
            get { return separateFiles; }
            set { separateFiles = value; }
        }

        private string moduleName;
        public string ModuleName
        {
            get { return moduleName ?? MigrationManager.DefaultModuleName; }
            set { moduleName = value; }
        }

        private List<string> extraArguments = new List<string>();
        public List<string> ExtraArguments
        {
            get { return extraArguments; }
        }

        private string server;
        public string Server
        {
            get { return server; }
            set { server = value; }
        }

        private string database;
        public string Database
        {
            get { return database; }
            set { database = value; }
        }

        private string user;
        public string User
        {
            get { return user; }
            set { user = value; }
        }

        private string pass;
        public string Pass
        {
            get { return pass; }
            set { pass = value; }
        }

		public string Output{ get; set; }
        #endregion

        void ParseCommandLine(string[] args)
        {
            if (args.Length == 0)
            {
                //throw new ArgumentException("No Arguements Found");
            }
            else
            {
                switch (args[0].ToLower())
                {
                    case "migrate":
                    Operation = MigrationOperation.Migrate;
                    break;
                    case "generate":
                    Operation = MigrationOperation.Generate;
                    break;
                    case "auto":
                    Operation = MigrationOperation.AutoGenerate;
                    break;
                }

                bool connectionStringSet = false;
                for (int i = 1; i < args.Length; i++)
                {
                    string value;
                    string key = ParseOption(args[i], out value);
                    switch (key.ToLower())
                    {
                        case "f":
                        case "file":
                        case "filename":
							filename = value;
							break;
                        case "v":
                        case "version":
							int tmpVersion = 0;
							if (!int.TryParse(value, out tmpVersion))
							{
								Console.WriteLine("Unable to read version number");
							}
							else
							{
								Version = tmpVersion;
							}
							break;
                        case "c":
                        case "connection":
                        case "connectionstring":
							connectionStringSet = true;
							DbProvider.DefaultConnectionString = value;
							break;
                        case "m":
                        case "module":
							ModuleName = value;
							break;
                        case "sf":
                        case "separatefiles":
							separateFiles = true;
							break;
                        case "s":
                        case "server":
							Server = value;
							break;
                        case "db":
							Database = value;
							break;
                        case "debug":
							Console.ReadLine();
							break;
                        case "u":
                        case "user":
							User = value;
							break;
                        case "p":
                        case "pass":
							Pass = value;
							break;
                        case "o":
                        case "output":
							Output = value;
							break;
                        default:
							if (Regex.Match(args[i], @"^-{1,2}|^/").Success)
								throw new ArgumentException("Invalid argument: " + args[i]);
							else
								extraArguments.Add(args[i]);
							break;
                    }
                }

                if (!connectionStringSet)
                {
                    if (String.IsNullOrEmpty(User))
                    {
                        DbProvider.DefaultConnectionString =
                            string.Format("data source={0};initial catalog={1};Integrated Security=SSPI;", Server,
                                          Database);
                    }
                    else
                    {
                        DbProvider.DefaultConnectionString = string.Format("data source={0};initial catalog={1};user id={2};password={3}", Server,
                                          Database, User, Pass);
                    }
                }
            }
        }

        private static void OutputOptions()
        {
            Console.WriteLine("Welcome to RikMigrations Command Line Options Are:");
            Console.Write("\n");
            Console.WriteLine("    RikMigrataions.exe Operations Assembly [flags]");
            Console.WriteLine(@"Example: RikMigrations.exe migrate TestApp.exe -s:(local)\SQLEXPRESS -db:TestDB");
            Console.WriteLine("Operations: ");
            Console.WriteLine("             Migrate - Migrate to Version ");
            Console.WriteLine("             Auto - Generate Migrations from the database");
            Console.WriteLine("Flags:");
            Console.WriteLine("             f!file|filename - filename for generated file");
            Console.WriteLine("             sf|separatefile - Separate files. Use if you want a file for each schema object generated");
            Console.WriteLine("             v|version - version to migrate to");
            Console.WriteLine("             m|module - module to migrate");
            Console.WriteLine("             db - Target database Catalog");
            Console.WriteLine("             s|server - Target Data Source");
            Console.WriteLine("             u|user - Database user (if not used SSPI is default).");
            Console.WriteLine("             p|pass - User password (if user not provided, skipped");
        }

        string ParseOption(string arg, out string value)
        {
            // Remove option indicator
            arg = Regex.Replace(arg, @"^-{1,2}|^/", "");

            value = null;
            Match m = Regex.Match(arg, @"^(.*?)(((=|:)(.*)$)|$)");
            if (m.Success)
            {
                if (m.Groups[5].Success)
                    value = m.Groups[5].Value;
                return m.Groups[1].Value;
            }
            return null;
        }
    }
}